
const {
    logger,
    sleep,
    initPage2,
    closeBrowser,
    randBetween,
    avoidNoticeFreq,
    waitOtherWorker,
    updateErrorTimes,
    closeRun,
    lpush,
    get,
    set,
    expire,
    easyPushWechatMsg,
    tiPost,
} = require('./util');

const {
    syncExec,
} = require('./model'); 

const {
    readTask,
} = require('./ti_logic_read_task');

//全局捕获错误
process.on('unhandledRejection', error => {
    //...不处理处理...
});

let openSerials = [];//需要关注的规格

//每30秒重新拉取任务列表
(async () => {
    while (1) {
        const tasks = await readTask();
        if (!tasks) continue;
        const tmpSerials = [];
        for (const task of tasks) {
            if (task.status != 1) continue;
            tmpSerials.push(task.serial);
        }
        openSerials = tmpSerials;
        await sleep(30000);
    }
})();

//用随机数模拟页面滚动以及鼠标滑动
const randomScrollAndMouseMove = async page => {
    const x1 = randBetween(400, 1600);
    const y1 = randBetween(0, 300);
    const wait1 = randBetween(60, 120);
    const scrollY1 = randBetween(200, 500);
    logger('滚动页面到输入框处，并模拟鼠标滑动', x1, y1, wait1, scrollY1);
    await page.mouse.move(x1, y1, {steps:wait1});
    await page.evaluate(scrollY => {
        window.scrollTo(0, scrollY);
    }, scrollY1);
    const x2 = randBetween(200, 1500);
    const y2 = randBetween(300, 600);
    const wait2 = randBetween(60, 120);
    const scrollY2 = randBetween(500, 700);
    logger('模拟鼠标滑动', x2, y2, wait2, scrollY2);
    await page.mouse.move(x2, y2, {steps:wait2});
    await sleep(1000);
    await page.evaluate(scrollY => {
        window.scrollTo(0, scrollY);
    }, scrollY2);
}

const randomMoveAndClick = async page => {
    //鼠标随机移动4-6个地方
    const mouseMoveNum = randBetween(4, 6);
    logger('鼠标随机移动', mouseMoveNum, '次');
    for (let i=0; i<mouseMoveNum; i++) {
        const x = 10 + randBetween(100, 1700);
        const y = 110 + randBetween(200, 800);
        const steps = randBetween(30, 60);
        await page.mouse.move(x, y, {steps});
        await sleep(randBetween(200, 700));
    }

    logger('鼠标移动到输入框并点击');
    const targetInput = await page.$('ti-input');
    const box = await targetInput.boundingBox();
    const x1 = box.x + (box.width/2) - 3;
    const y1 = box.y + (box.height/2) - 2;
    const steps1 = randBetween(30, 60);
    await page.mouse.move(x1, y1, {steps:steps1});
    await page.mouse.click(x1, y1, {delay:200});
    await sleep(1000);
    logger('鼠标移出输入框并点击');
    const x2 = x1 - randBetween(100, 200);
    const y2 = y1 - randBetween(10, 200);
    const steps2 = randBetween(30, 60);
    await page.mouse.move(x2, y2, {steps:steps2});
    await page.mouse.click(x2, y2, {delay:100});
    await sleep(2000);
}

//程序主流程
(async () => {

    const page = await initPage2();
    logger('启动浏览器');
    try {
        await page.goto('https://www.ti.com.cn/zh-cn/ordering-resources/buying-tools/quick-add-to-cart.html');
        await page.waitForSelector('ti-input');
    } catch(e) {
        logger('打开快速下单页失败，将重启浏览器');
        await closeBrowser();
        await sleep(5000);
        return process.exit(1);
    }
    await randomScrollAndMouseMove(page);

    let timeoutCount = 0;
    let counter = 0;
    while (1) {
        logger('第', ++counter, '轮');

        //如果有其他进程在跑，等待
        //await waitOtherWorker();

        //鼠标随机移动和点击，有可能被卡住。如果超过n秒未完成，则强制跳过
        await Promise.race([
            randomMoveAndClick(page),
            sleep(20000),
        ]);

        logger('查询库存');
        try {
            const ret = await page.evaluate(async (serialStr) => {
                const ajax = () => {
                    return new Promise(resolve => {
                        const timer = setTimeout(() => {
                            resolve('timeout');
                        }, 20000);
                        const xhr = new XMLHttpRequest();
                        xhr.open('post', 'https://www.ti.com.cn/storeservices/cart/inventory', true);
                        xhr.setRequestHeader('Content-Type', 'application/json');
                        xhr.onreadystatechange = function(){
                            if (xhr.readyState == 4) {
                                if (xhr.status == 200) {
                                    resolve(xhr.responseText);
                                }else if (xhr.status == 428) {
                                    resolve(xhr.statusText);
                                    const retJson2 = JSON.parse(xhr.responseText);
                                    sleep(retJson2['chlg_duration'] * 1000);
                                }else {
                                    resolve(xhr.statusText);
                                }
                                clearTimeout(timer);
                            }
                        };
                        xhr.send(serialStr);
                    });
                }
                const ret = await ajax();
                return ret;
            }, JSON.stringify(openSerials.sort(() => 0.5-Math.random())));

            logger('查询结果', ret);
            if (ret[0] == '{') {
                timeoutCount = 0;
                const retJson = JSON.parse(ret);
                let found = 0;
                for (const v of retJson.opn_list) {
                    if (v.purchase_flag == 'Y' && v.quantity >= 1) {
                        found = 1;
                        const serial = v.orderable_number;
                        const stock = v.quantity;
                        const msg = `规格 ${serial} 发现有 ${stock} 库存`;
                        logger(msg);

                        //门槛是250
                        if (stock < 250) continue;

                        //如果对应规格最近1小时内报告超过3次，则不再告警，避免信息轰炸
                        if (await avoidNoticeFreq(serial)) {
                            await easyPushWechatMsg(msg);
                        }

                        //至少有100件才尝试下单
                        //if (stock >= 100) {
                            //最近是否成功加过购物车
                            const recentSuccKey = 'ti_add_cart_succ_'+serial;
                            const isRecentSucc = await get(recentSuccKey);
                            //最近加购物车是否失败
                            const recentFailKey = 'ti_add_cart_fail_'+serial;
                            const isRecentFail = await get(recentFailKey);

                            if (!isRecentSucc && !isRecentFail) {
                                const url = 'https://www.ti.com.cn/occservices/v2/ti/addtocart';
                                const postData = JSON.stringify({
                                    'cartRequestList':[
                                        {
                                            'opnId':serial,
                                            'quantity':stock,
                                            'packageOption':null,
                                            'tiAddtoCartSource':'ti.com-quickcart',
                                        }
                                    ],
                                    currency:'CNY',
                                });
                                const referer = 'https://www.ti.com.cn/zh-cn/ordering-resources/buying-tools/quick-add-to-cart.html';

                                //最多尝试加3次购物车
                                let failCount = 0;
                                let succ = 0;
                                for (let i=0; i<3; i++) {
                                    try {
                                        //const ret = await tiPost(url, postData, referer);

                                        const cookie = await get('ti_worker_cookie');

                                        const cmdStr = `curl --compressed \
                                        -H 'Host: www.ti.com.cn' \
                                        -H 'Connection: keep-alive' \
                                        -H 'sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"' \
                                        -H 'sec-ch-ua-mobile: ?0' \
                                        -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36" \
                                        -H "Content-Type: application/json" \
                                        -H 'X-Sec-Clge-Req-Type: ajax' \
                                        -H 'Expires: 0' \
                                        -H "Cache-Control: no-store, must-revalidate" \
                                        -H 'sec-ch-ua-platform: "macOS"' \
                                        -H 'Accept: */*' \
                                        -H 'Origin: https://www.ti.com.cn' \
                                        -H 'Sec-Fetch-Site: same-origin' \
                                        -H 'Sec-Fetch-Mode: cors' \
                                        -H 'Sec-Fetch-Dest: empty' \
                                        -H 'Referer: https://www.ti.com.cn/ordering-resources/buying-tools/quick-add-to-cart.html' \
                                        -H 'Accept-Encoding: gzip, deflate, br' \
                                        -H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8' \
                                        -H 'Cookie: ${cookie}' \
                                        -d '{"cartRequestList":[{"packageOption":null,"opnId":"${serial}","quantity":"${stock}","tiAddtoCartSource":"store-pdp","sparam":""}],"currency":"CNY"}' \
                                        https://www.ti.com.cn/occservices/v2/ti/addtocart -v`;

                                        ret = await syncExec(cmdStr);

                                        //const retJson = JSON.parse(ret);
                                        if (ret.indexOf('cartId') > -1) {
                                            succ = 1;
                                            const msg = `${serial}加购物车${stock}成功`;
                                            logger(msg, ret);
                                            //推送微信通知
                                            await easyPushWechatMsg(msg);

                                            //推送到redis，等待下单脚本进行下单操作
                                            await lpush('ti_worker_order', serial);

                                            //记录到redis，最近1小时不再尝试加购物车
                                            await set(recentSuccKey, 1);
                                            await expire(recentSuccKey, 3600);

                                            break;
                                        } else {
                                            failCount++;
                                            logger(`加购物车第${failCount}次失败`);
                                            await sleep(5000);
                                        }
                                    } catch(e) {
                                        logger('加购物车异常', serial, e);
                                        await sleep(5000);
                                    }
                                }
                                if (!succ) {
                                    //发送通知，等待人工操作
                                    const msg = `${serial}加购物车失败`;
                                    await easyPushWechatMsg(msg);

                                    //记录到redis，最近5分钟内不再尝试加购物车
                                    await set(recentFailKey, 1);
                                    await expire(recentFailKey, 300);
                                }
                            }
                        //}
                    }
                }
                if (!found) {
                    logger('本轮未检测到有库存');
                }
                await sleep(2000);
            } else {
                //返回内容不是JSON，可能是被拦截了，等n秒后再重新请求
                await sleep(10000);
                timeoutCount++;
                await updateErrorTimes(timeoutCount);
                //连续n次timeout，退出重启浏览器
                if (timeoutCount >= 2) {
                    break;
                }
            }
        } catch(e) {
            logger('查询出错', e);
            await sleep(5000);
            continue;
        }
    }

    await closeRun();
    logger('失败过多，关闭浏览器');
    await closeBrowser();
    process.exit(1);

})();

